#ifdef _WIN32
#include <windows.h>
#else
#include <GL/glx.h>
#endif

#include <iostream>

#include "pyramid.h"
#include "robot.h"

#include <math.h>
#define PI 3.14159265

#define BUFFER_OFFSET(i) ((char *)NULL + (i))

Pyramid::Pyramid()
{
}

void Pyramid::initializeVertexBuffer4()
{
    const float radius = 5.0f;
	const float height= 0.0f;
    //Push back 8 vertices that make up a cube
	m_vertices4.push_back(Vertex(0.0f,0.0f,0.0f));
    m_vertices4.push_back(Vertex((float)(radius*sin(30*PI/180)), 0.0f,  (float)(radius*cos(30*PI/180))));
    m_vertices4.push_back(Vertex((float)(-radius*sin(30*PI/180)), 0.0f, (float)(radius*cos(30*PI/180))));
    m_vertices4.push_back(Vertex(0.0f, (float)(radius*cos(30*PI/180)),  (float)(radius*cos(30*PI/180)/2)));

    //Push back the indices that make up the triangles for each face.
    m_indices4.push_back(0);
    m_indices4.push_back(1);
    m_indices4.push_back(2);
    m_indices4.push_back(0);

    m_indices4.push_back(0);
    m_indices4.push_back(1);
	m_indices4.push_back(3);
	m_indices4.push_back(0);

	m_indices4.push_back(0);
	m_indices4.push_back(2);
	m_indices4.push_back(3);
	m_indices4.push_back(0);

	m_indices4.push_back(1);
	m_indices4.push_back(2);
	m_indices4.push_back(3);
	m_indices4.push_back(1);

    glBindBuffer(GL_ARRAY_BUFFER, m_vbos[VERTEX_BUFFER]); //Bind the vertex buffer
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * m_vertices4.size(), &m_vertices4[0], GL_STATIC_DRAW); //Send the data to OpenGL

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_vbos[INDEX_BUFFER]); //Bind the vertex buffer
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * m_indices4.size(), &m_indices4[0], GL_STATIC_DRAW); //Send the data to OpenGL
}

void Pyramid::initializeVertexBuffer5()
{
    const float radius = 2.0f;
	const float height= 0.0f;
    //Push back 8 vertices that make up a cube
    m_vertices5.push_back(Vertex(-radius, 0.0f,  -radius));
    m_vertices5.push_back(Vertex(-radius, 0.0f, radius));
    m_vertices5.push_back(Vertex(radius, 0.0f, radius));
    m_vertices5.push_back(Vertex(radius, 0.0f,  -radius));
	m_vertices5.push_back(Vertex(0.0f, 2*radius,  0.0f));

    //Push back the indices that make up the triangles for each face.
    m_indices5.push_back(0);
    m_indices5.push_back(2);
    m_indices5.push_back(3);
    m_indices5.push_back(0);
    m_indices5.push_back(1);
	m_indices5.push_back(2);

	m_indices5.push_back(0);
	m_indices5.push_back(1);
	m_indices5.push_back(4);
	m_indices5.push_back(0);

	m_indices5.push_back(1);
	m_indices5.push_back(2);
	m_indices5.push_back(4);
	m_indices5.push_back(1);

	m_indices5.push_back(2);
	m_indices5.push_back(3);
	m_indices5.push_back(4);
	m_indices5.push_back(2);

	m_indices5.push_back(3);
	m_indices5.push_back(0);
	m_indices5.push_back(4);
	m_indices5.push_back(3);



    glBindBuffer(GL_ARRAY_BUFFER, m_vbos[VERTEX_BUFFER]); //Bind the vertex buffer
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * m_vertices5.size(), &m_vertices5[0], GL_STATIC_DRAW); //Send the data to OpenGL

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_vbos[INDEX_BUFFER]); //Bind the vertex buffer
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * m_indices5.size(), &m_indices5[0], GL_STATIC_DRAW); //Send the data to OpenGL
}
void Pyramid::initializeVertexBufferDiamond()
{
    const float radius = 2.0f;
	const float height= 0.0f;
    //Push back 8 vertices that make up a cube
    m_verticesDiamond.push_back(Vertex(-radius, 0.0f,  -radius));
    m_verticesDiamond.push_back(Vertex(-radius, 0.0f, radius));
    m_verticesDiamond.push_back(Vertex(radius, 0.0f, radius));
    m_verticesDiamond.push_back(Vertex(radius, 0.0f,  -radius));
	m_verticesDiamond.push_back(Vertex(0.0f, 2*radius,  0.0f));
	m_verticesDiamond.push_back(Vertex(0.0f, -2*radius,  0.0f));


    //Push back the indices that make up the triangles for each face.
	//top half
	m_indicesDiamond.push_back(0);
	m_indicesDiamond.push_back(1);
	m_indicesDiamond.push_back(4);
	m_indicesDiamond.push_back(0);

	m_indicesDiamond.push_back(1);
	m_indicesDiamond.push_back(2);
	m_indicesDiamond.push_back(4);
	m_indicesDiamond.push_back(1);

	m_indicesDiamond.push_back(2);
	m_indicesDiamond.push_back(3);
	m_indicesDiamond.push_back(4);
	m_indicesDiamond.push_back(2);

	m_indicesDiamond.push_back(3);
	m_indicesDiamond.push_back(0);
	m_indicesDiamond.push_back(4);
	m_indicesDiamond.push_back(3);

	//bottom half
	m_indicesDiamond.push_back(0);
	m_indicesDiamond.push_back(1);
	m_indicesDiamond.push_back(5);
	m_indicesDiamond.push_back(0);

	m_indicesDiamond.push_back(1);
	m_indicesDiamond.push_back(2);
	m_indicesDiamond.push_back(5);
	m_indicesDiamond.push_back(1);

	m_indicesDiamond.push_back(2);
	m_indicesDiamond.push_back(3);
	m_indicesDiamond.push_back(5);
	m_indicesDiamond.push_back(2);

	m_indicesDiamond.push_back(3);
	m_indicesDiamond.push_back(0);
	m_indicesDiamond.push_back(5);
	m_indicesDiamond.push_back(3);


    glBindBuffer(GL_ARRAY_BUFFER, m_vbos[VERTEX_BUFFER]); //Bind the vertex buffer
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * m_verticesDiamond.size(), &m_verticesDiamond[0], GL_STATIC_DRAW); //Send the data to OpenGL

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_vbos[INDEX_BUFFER]); //Bind the vertex buffer
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * m_indicesDiamond.size(), &m_indicesDiamond[0], GL_STATIC_DRAW); //Send the data to OpenGL
}
void Pyramid::initializeVertexColors4()
{
    /*
        We build an array of colors, 8 reds, 8 blues, 8 yellows and 8 whites.
        This is because there are 8 vertices in a cube, we switch the color by
        setting the BUFFER_OFFSET to glColorPointer to point at each block
        of colors before rendering with glDrawElements
    */

    float purple [] = { 1.0f, 0.0f, 1.0f };
    for (int i = 0; i < 4; ++i) {
        m_colorBuffer4.push_back(Color(purple[0], purple[1], purple[2]));
    }
    //Send the color data to OpenGL
    glBindBuffer(GL_ARRAY_BUFFER, m_vbos[COLOR_BUFFER]); //Bind the vertex buffer
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * m_colorBuffer4.size(), &m_colorBuffer4[0], GL_STATIC_DRAW); //Send the data to OpenGL
}

void Pyramid::initializeVertexColors5()
{
    /*
        We build an array of colors, 8 reds, 8 blues, 8 yellows and 8 whites.
        This is because there are 8 vertices in a cube, we switch the color by
        setting the BUFFER_OFFSET to glColorPointer to point at each block
        of colors before rendering with glDrawElements
    */

    float blue [] = { 0.0f, 0.8f, 0.0f };
    for (int i = 0; i < 5; ++i) {
        m_colorBuffer5.push_back(Color(blue[0], blue[1], blue[2]));
    }
    //Send the color data to OpenGL
    glBindBuffer(GL_ARRAY_BUFFER, m_vbos[COLOR_BUFFER]); //Bind the vertex buffer
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * m_colorBuffer5.size(), &m_colorBuffer5[0], GL_STATIC_DRAW); //Send the data to OpenGL
}
void Pyramid::initializeVertexColorsDiamond()
{
    /*
        We build an array of colors, 8 reds, 8 blues, 8 yellows and 8 whites.
        This is because there are 8 vertices in a cube, we switch the color by
        setting the BUFFER_OFFSET to glColorPointer to point at each block
        of colors before rendering with glDrawElements
    */

    float blue [] = { 0.0f, 0.8f, 0.0f };
    for (int i = 0; i < 6; ++i) {
        m_colorBufferDiamond.push_back(Color(blue[0], blue[1], blue[2]));
    }
    //Send the color data to OpenGL
    glBindBuffer(GL_ARRAY_BUFFER, m_vbos[COLOR_BUFFER]); //Bind the vertex buffer
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * m_colorBufferDiamond.size(), &m_colorBufferDiamond[0], GL_STATIC_DRAW); //Send the data to OpenGL
}

void Pyramid::render4(GLfloat rotation)
{
	initialize4();
	//glScalef(30.0f, 30.0f, 30.0f);
    glLoadIdentity();					// reset matrix
	glTranslatef(0.0f, 5.0f, -30.0f);
	glRotatef(rotation, 0.0f, 1.0f, 0.0f);
    glDrawElements(GL_TRIANGLES, m_indices4.size(), GL_UNSIGNED_INT, 0);

}

void Pyramid::render5(GLfloat rotation)
{
	initialize5();
	//glScalef(30.0f, 30.0f, 30.0f);
    glLoadIdentity();					// reset matrix
	glTranslatef(-10.0f, 5.0f, -30.0f);
	glRotatef(rotation, 1.0f, 0.0f, 0.0f);
    glDrawElements(GL_TRIANGLES, m_indices5.size(), GL_UNSIGNED_INT, 0);

}

void Pyramid::renderDiamond(GLfloat rotation)
{
	initializeDiamond();
	//glScalef(30.0f, 30.0f, 30.0f);
    //glLoadIdentity();					// reset matrix
	glTranslatef(0.0f, 10.0f, -30.0f);
	glRotatef(rotation, 0.0f, 1.0f, 0.0f);
    glDrawElements(GL_TRIANGLES, m_indicesDiamond.size(), GL_UNSIGNED_INT, 0);

}

void Pyramid::renderDiamond2(GLfloat rotation)
{
	initializeDiamond();
	//glScalef(30.0f, 30.0f, 30.0f);
    //glLoadIdentity();					// reset matrix
	glTranslatef(0.0f, 0.0f, -15.0f);
	glRotatef(rotation, 0.0f, 1.0f, 0.0f);
    glDrawElements(GL_TRIANGLES, m_indicesDiamond.size(), GL_UNSIGNED_INT, 0);

}

bool Pyramid::initialize4()
{
#ifdef _WIN32
    glGenBuffers = (PFNGLGENBUFFERSARBPROC)wglGetProcAddress("glGenBuffers");
    glBindBuffer = (PFNGLBINDBUFFERPROC)wglGetProcAddress("glBindBuffer");
    glBufferData = (PFNGLBUFFERDATAPROC)wglGetProcAddress("glBufferData");
#else
    glGenBuffers = (PFNGLGENBUFFERSARBPROC)glXGetProcAddress((const GLubyte*)"glGenBuffers");
    glBindBuffer = (PFNGLBINDBUFFERPROC)glXGetProcAddress((const GLubyte*)"glBindBuffer");
    glBufferData = (PFNGLBUFFERDATAPROC)glXGetProcAddress((const GLubyte*)"glBufferData");
#endif

    if (!glGenBuffers || !glBindBuffer || !glBufferData)
    {
        std::cerr << "VBOs are not supported by your graphics card" << std::endl;
        return false;
    }

    glGenBuffers(LAST_BUFFER, m_vbos); //Generate a buffer for the vertices, indices and colors

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);

    initializeVertexBuffer4(); //Build up the array of vertices for the cube
    initializeVertexColors4(); //Build up an array of colors for the robot

    //Set the vertex pointer for the cube
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_vbos[INDEX_BUFFER]); //Bind the vertex buffer
    glBindBuffer(GL_ARRAY_BUFFER, m_vbos[VERTEX_BUFFER]);
    glVertexPointer(3, GL_FLOAT, 0, 0);

    //Bind the default color as white, this changes depending on the part of the robot we are drawing
    glBindBuffer(GL_ARRAY_BUFFER, m_vbos[COLOR_BUFFER]);
    glColorPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(WHITE_OFFSET)); //Default color white


    return true;
}

bool Pyramid::initialize5()
{
#ifdef _WIN32
    glGenBuffers = (PFNGLGENBUFFERSARBPROC)wglGetProcAddress("glGenBuffers");
    glBindBuffer = (PFNGLBINDBUFFERPROC)wglGetProcAddress("glBindBuffer");
    glBufferData = (PFNGLBUFFERDATAPROC)wglGetProcAddress("glBufferData");
#else
    glGenBuffers = (PFNGLGENBUFFERSARBPROC)glXGetProcAddress((const GLubyte*)"glGenBuffers");
    glBindBuffer = (PFNGLBINDBUFFERPROC)glXGetProcAddress((const GLubyte*)"glBindBuffer");
    glBufferData = (PFNGLBUFFERDATAPROC)glXGetProcAddress((const GLubyte*)"glBufferData");
#endif

    if (!glGenBuffers || !glBindBuffer || !glBufferData)
    {
        std::cerr << "VBOs are not supported by your graphics card" << std::endl;
        return false;
    }

    glGenBuffers(LAST_BUFFER, m_vbos); //Generate a buffer for the vertices, indices and colors

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);

    initializeVertexBuffer5(); //Build up the array of vertices for the cube
    initializeVertexColors5(); //Build up an array of colors for the robot

    //Set the vertex pointer for the cube
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_vbos[INDEX_BUFFER]); //Bind the vertex buffer
    glBindBuffer(GL_ARRAY_BUFFER, m_vbos[VERTEX_BUFFER]);
    glVertexPointer(3, GL_FLOAT, 0, 0);

    //Bind the default color as white, this changes depending on the part of the robot we are drawing
    glBindBuffer(GL_ARRAY_BUFFER, m_vbos[COLOR_BUFFER]);
    glColorPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(WHITE_OFFSET)); //Default color white


    return true;
}
bool Pyramid::initializeDiamond()
{
#ifdef _WIN32
    glGenBuffers = (PFNGLGENBUFFERSARBPROC)wglGetProcAddress("glGenBuffers");
    glBindBuffer = (PFNGLBINDBUFFERPROC)wglGetProcAddress("glBindBuffer");
    glBufferData = (PFNGLBUFFERDATAPROC)wglGetProcAddress("glBufferData");
#else
    glGenBuffers = (PFNGLGENBUFFERSARBPROC)glXGetProcAddress((const GLubyte*)"glGenBuffers");
    glBindBuffer = (PFNGLBINDBUFFERPROC)glXGetProcAddress((const GLubyte*)"glBindBuffer");
    glBufferData = (PFNGLBUFFERDATAPROC)glXGetProcAddress((const GLubyte*)"glBufferData");
#endif

    if (!glGenBuffers || !glBindBuffer || !glBufferData)
    {
        std::cerr << "VBOs are not supported by your graphics card" << std::endl;
        return false;
    }

    glGenBuffers(LAST_BUFFER, m_vbos); //Generate a buffer for the vertices, indices and colors

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);

    initializeVertexBufferDiamond(); //Build up the array of vertices for the cube
    initializeVertexColorsDiamond(); //Build up an array of colors for the robot

    //Set the vertex pointer for the cube
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_vbos[INDEX_BUFFER]); //Bind the vertex buffer
    glBindBuffer(GL_ARRAY_BUFFER, m_vbos[VERTEX_BUFFER]);
    glVertexPointer(3, GL_FLOAT, 0, 0);

    //Bind the default color as white, this changes depending on the part of the robot we are drawing
    glBindBuffer(GL_ARRAY_BUFFER, m_vbos[COLOR_BUFFER]);
    glColorPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(WHITE_OFFSET)); //Default color white


    return true;
}